package com.example.demo2.service;

import com.example.demo2.entity.ComparisonResults;
import com.example.demo2.entity.Result;
import com.example.demo2.entity.UploadedData;
import com.example.demo2.mapper.ComparisonResultsMapper;
import com.example.demo2.util.JobProgress;
import com.example.demo2.util.ResultIndex;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Service
public class ComparisonBatchProcessService {

    @Autowired
    private UploadedDataService uploadedDataService;

    @Autowired
    private ComparisonResultsMapper comparisonResultsMapper;

    private static final Logger logger = LoggerFactory.getLogger(ComparisonBatchProcessService.class);

    @Async
    @Transactional
    public void processUploadedDataBatch(String jobId, int batchNumber, int batchSize, String uploadName,
                                         ResultIndex resultIndex, double tolerance, int totalUploadedData,
                                         Map<String, JobProgress> progressMap, String comparisonName) {
        logger.info("Starting to process batch {} for job {}", batchNumber, jobId);
        int offset = batchNumber * batchSize;
        List<UploadedData> uploadedDataBatch = uploadedDataService.getUploadedDataByNameBatch(uploadName, offset, batchSize);

        List<ComparisonResults> batchResults = new ArrayList<>();
        for (UploadedData data : uploadedDataBatch) {
            logger.debug("Processing data: molecularWeight: {}, rtMin: {}", data.getMolecularWeight(), data.getRtMin());
            BigDecimal toleranceBD = new BigDecimal(tolerance);
            BigDecimal lowerBound = data.getMolecularWeight().multiply(BigDecimal.ONE.subtract(toleranceBD));
            BigDecimal upperBound = data.getMolecularWeight().multiply(BigDecimal.ONE.add(toleranceBD));

            List<Result> matchingResults = resultIndex.findResultsInRange(lowerBound, upperBound);

            for (Result result : matchingResults) {
                ComparisonResults comparisonResult = new ComparisonResults(
                        data.getMolecularWeight(),
                        data.getRtMin(),
                        result.getResult(),
                        result.getContent(),
                        result.getName(),
                        result.getFormula(),
                        comparisonName
                );
                batchResults.add(comparisonResult);
            }

            JobProgress progress = progressMap.get(jobId);
            progress.incrementCompletedItems();
            int progressPercentage = (int) ((double) progress.getCompletedItems() / totalUploadedData * 100);
            progress.setProgress(progressPercentage);
        }

        if (!batchResults.isEmpty()) {
            try {
                logger.info("Attempting to insert {} comparison results for job {}", batchResults.size(), jobId);
                comparisonResultsMapper.batchInsertComparisonResults(batchResults);
                logger.info("Successfully inserted {} comparison results for job {}", batchResults.size(), jobId);
            } catch (Exception e) {
                logger.error("Error inserting comparison results for job {}: {}", jobId, e.getMessage(), e);
            }
        } else {
            logger.info("No comparison results to insert for batch {} of job {}", batchNumber, jobId);
        }

        logger.info("Finished processing batch {} for job {}", batchNumber, jobId);
    }

    @Async
    public void finalizeComparison(String jobId, String comparisonName) {
        long count = comparisonResultsMapper.countByComparisonName(comparisonName);
        logger.info("Total comparison results for job {} after all insertions: {}", jobId, count);
    }
}